home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / dev / c / Vperf5.1-src.lha / Viewperf5.1 / tools / convert.c next >
Encoding:
C/C++ Source or Header  |  1997-02-12  |  29.5 KB  |  1,051 lines

  1. /*
  2. // Permission to use, copy, modify, and distribute this software and its
  3. // documentation for any purpose and without fee is hereby granted, provided
  4. // that the above copyright notice appear in all copies and that both that
  5. // copyright notice and this permission notice appear in supporting
  6. // documentation, and that the name of I.B.M. not be used in advertising
  7. // or publicity pertaining to distribution of the software without specific,
  8. // written prior permission. I.B.M. makes no representations about the
  9. // suitability of this software for any purpose.  It is provided "as is"
  10. // without express or implied warranty.
  11. //
  12. // I.B.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  13. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL I.B.M.
  14. // BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  16. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  17. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. //
  19. // DB Murrell
  20. // * 6/15/93
  21. */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <stdarg.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include <time.h>
  29. #include <sys/time.h>
  30. #include <sys/types.h>
  31. #include <sys/errno.h>
  32.  
  33. #define VERSION        "CONVERT Version 1.0 (6/15/93)"
  34. #define ERROR_OUT    stderr
  35. #define END_OF_TEXT      "### EOT ###"
  36. #define FLAGS        "hH?bBaAvVmMpPoOcC"
  37. #define N_POLY_TYPES    3
  38. #ifndef TRUE
  39.   #define TRUE 1
  40. #endif
  41. #ifndef FALSE
  42.   #define FALSE 0
  43. #endif
  44.  
  45. typedef int int32;              /* 32 bit integer */
  46. typedef unsigned int uint32;    /* 32 bit unsigned integer */
  47. typedef float float32;          /* 32 bit single precision float */
  48. typedef enum {False = 0, True}            Boolean;
  49. typedef enum {INFORMATION, WARNING, FATAL}    Severity;
  50. typedef enum {BINARY, ASCII}            Output_Mode;
  51. typedef enum {MESH, POLYGON}            Input_Type;
  52. typedef enum {COORDINATES = 0, ELEMENTS, NORMS}    Poly_Type;
  53.  
  54. static char    *self_name = NULL;
  55.  
  56. /*
  57.  * Polygon information table
  58.  */
  59. static struct {
  60.     Poly_Type    type;
  61.     char     *ext;
  62.     char    *desc;
  63. } poly_table[] = {
  64.     { COORDINATES, ".coor",  "Coordinate Data" },
  65.     { ELEMENTS,    ".elem",  "Element Data"    },
  66.     { NORMS,       ".vnorm", "Vector Normals"  }
  67. };
  68.  
  69. /*
  70.  * Help text
  71.  */
  72. static char *help_text[] = {
  73.     "Converts viewperf polygon and mesh files to and from binary",
  74.     "and ASCII formats",
  75.     "",
  76.     "USAGE:   convert [options] <input_file> <output_file>",
  77.     "",
  78.     "options:",
  79.     "   -[hH?]     Display this message",
  80.     "",
  81.     "   -[bB]      Convert to binary (assumes ASCII input)",
  82.     "",
  83.     "   -[aA]      Convert to ASCII  (assumes binary input)",
  84.     "",
  85.     "   -[vV]      Verbose mode",
  86.     "",
  87.     "   -[mM]      Input file is full path to viewperf mesh data",
  88.     "",
  89.     "   -[pPoO]    Input file is path prefix to viewperf polygon data",
  90.     "              (suffixes .coor, .elem, and .vnorm are added by convert)",
  91.     "",
  92.     "   -[cC]      Add comments to ASCII output files",
  93.     "",
  94.     "Input and output files default to stdin, and stdout (respectively) if",
  95.     "left unspecified",
  96.     END_OF_TEXT
  97. };
  98.  
  99. /*
  100.  ********************************************************************
  101.  *
  102.  * Swap32 -- Byte swap a 32 bit datum to convert between big
  103.  *           and little endian formats.
  104.  *
  105.  ********************************************************************
  106.  */
  107. static void Swap32(void *src_void, void *dst_void, size_t length)
  108. {
  109.   register uint32 tmp;
  110.   uint32 *src = (uint32 *) src_void;
  111.   uint32 *dst = (uint32 *) dst_void;
  112.   size_t i;
  113.  
  114.   for (i = 0; i < length; i++) {
  115.     tmp = src[i];
  116.     tmp &= 0xffffffff;
  117.     tmp = ((tmp >> 24) | (tmp << 24) | 
  118.            ((tmp >> 8) & 0xff00) | ((tmp << 8) & 0xff0000));
  119.     dst[i] = tmp;
  120.   }
  121. }
  122.  
  123. /*
  124.  ********************************************************************
  125.  *
  126.  * Error -- Error reporting
  127.  *
  128.  ********************************************************************
  129.  */
  130. static void Error(Severity sev, char *file, unsigned line, 
  131.        char *procedure, char *format, ...)
  132. {
  133.     char        level[16];
  134.     va_list     args;
  135.  
  136.     /*
  137.      * Sanity check
  138.      */
  139.     if (file == NULL || self_name == NULL || procedure == NULL)
  140.         return;
  141.  
  142.     va_start(args, format);
  143.  
  144.     switch (sev)
  145.     {
  146.     case INFORMATION:
  147.         strcpy(level, "NOTE");
  148.         break;
  149.     case WARNING:
  150.         strcpy(level, "*** WARNING");
  151.         break;
  152.     default:
  153.         strcpy(level, ">>> FATAL");
  154.         break;
  155.     }
  156.  
  157.     fprintf(ERROR_OUT, "%s ('%s'@%d, %s::%s) -\n\t", 
  158.         level, file, line, self_name, procedure);
  159. /*
  160.     if (format == NULL)
  161.         fprintf(ERROR_OUT, "%s", strerror(errno));
  162.     else
  163.         vfprintf(ERROR_OUT, format, args);
  164. */
  165.     fprintf(ERROR_OUT, "\n");
  166.     fflush(ERROR_OUT);
  167.  
  168.     va_end(args);
  169.  
  170.     if (sev == FATAL)
  171.         exit(1);
  172. } /* Error */
  173.  
  174. /*
  175.  ********************************************************************
  176.  *
  177.  * Expand -- Stretch a storage area to at least size (bytes) given
  178.  *
  179.  ********************************************************************
  180.  */
  181. static void Expand(char **store, size_t size)
  182. {
  183.     /*
  184.      * Sanity check
  185.      */
  186.     if (store == NULL || size == 0)
  187.     return;
  188.  
  189.     if ((*store) == NULL)
  190.     {
  191.         if (((*store) = (char *)malloc(size)) == NULL)
  192.             Error(FATAL, __FILE__, __LINE__, "Expand", NULL);
  193.     }
  194.     else if (((*store) = (char *)realloc(*store, size)) == NULL)
  195.         Error(FATAL, __FILE__, __LINE__, "Expand", NULL);
  196. } /* Expand */
  197.  
  198. /*
  199.  ********************************************************************
  200.  *
  201.  * Str_Dup -- Generate copy of string argument
  202.  *
  203.  ********************************************************************
  204.  */
  205. static void Str_Dup(char **dest, char *src)
  206. {
  207.     if (src == NULL)
  208.     {
  209.         if (*dest != NULL)
  210.             free(*dest);
  211.         *dest = NULL;
  212.         return;
  213.     } /* if */
  214.  
  215.     else if (*dest == NULL)
  216.     {
  217.         if ((*dest = (char *)malloc(strlen(src) + 1)) == NULL)
  218.         Error(FATAL, __FILE__, __LINE__, "Str_Dup", NULL);
  219.     } /* else if */
  220.  
  221.     else if ((*dest = (char *)realloc(*dest, strlen(src) + 1)) == NULL)
  222.     Error(FATAL, __FILE__, __LINE__, "Str_Dup", NULL);
  223.  
  224.     strcpy(*dest, src);
  225. } /* Str_Dup */
  226.  
  227. /*
  228.  ********************************************************************
  229.  *
  230.  * Str_Append -- Tack a list of strings onto the end of the first,
  231.  *         expanding the first if necessary.
  232.  *
  233.  ********************************************************************
  234.  */
  235. static void Str_Append(char **dest, ...)
  236. {
  237.     va_list     args;
  238.     char        *src;
  239.  
  240.     /*
  241.      * Sanity checks
  242.      */
  243.     if (dest == NULL)
  244.         return;
  245.  
  246.     va_start(args, dest);
  247.     while ((src = (char *)va_arg(args, char*)) != NULL)
  248.     {
  249.         if ((*dest) == NULL)
  250.         {
  251.         Expand(dest, (strlen(src) + 1) * sizeof(char));
  252.             strcpy(*dest, src);
  253.         } /* if */
  254.         else
  255.         {
  256.         Expand(dest, (strlen(*dest) + strlen(src) + 1) * sizeof(char));
  257.             strcat(*dest, src);
  258.         } /* else */
  259.     } /* while */
  260.     va_end(args);
  261. } /* Str_Append */
  262.  
  263. /*
  264.  ********************************************************************
  265.  *
  266.  * Show_Help_Text -- Text for help message
  267.  *
  268.  ********************************************************************
  269.  */
  270. static void Show_Help_Text(void)
  271. {
  272.     register unsigned i = 0;
  273.  
  274.     fprintf(stderr, "\t\t\t%s\n\n", VERSION);
  275.     while (strcmp(help_text[i], END_OF_TEXT) != 0)
  276.         fprintf(stderr, "%s\n", help_text[i++]);
  277. } /* Show_Help_Text */
  278.  
  279. /*
  280.  ********************************************************************
  281.  *
  282.  * Scan -- scan past comments and white space
  283.  *
  284.  ********************************************************************
  285.  */
  286. static void Scan(FILE *fp)
  287. {
  288.     int c;
  289.  
  290.     /*
  291.      * Sanity check
  292.      */
  293.     if (fp == NULL)
  294.         return;
  295.  
  296.     while (!feof(fp))
  297.     {
  298.     c = fgetc(fp);
  299.  
  300.         if (isspace(c))
  301.         continue;
  302.  
  303.     else if (c == '#')
  304.     {
  305.         while (((c = fgetc(fp)) != EOF) && (c != '\n'))
  306.         ;
  307.         continue;
  308.     } /* else if */
  309.  
  310.     else if (c != EOF)
  311.     {
  312.         ungetc(c, fp);
  313.         break;
  314.     } /* else */
  315.     } /* while */
  316.  
  317. } /* Scan */
  318.  
  319. /*
  320.  ********************************************************************
  321.  *
  322.  * M A I N
  323.  *
  324.  ********************************************************************
  325.  */
  326. void main(int argc, char *argv[])
  327. {
  328.     Output_Mode    output_mode = ASCII;
  329.     Input_Type    input_type = MESH;
  330.     Boolean    verbose = False;
  331.     Boolean    help = False;
  332.     Boolean    comments = False;
  333.  
  334.     int        option;
  335.     char    *input_file_path = NULL;
  336.     char    *output_file_path = NULL;
  337.  
  338.     FILE    *fp_input = NULL;
  339.     FILE    *fp_output = NULL;
  340.  
  341.     time_t    now = time(NULL);
  342.     char    time_string[256];
  343.     void       *ptr;
  344.     union {
  345.       int32    testWord;
  346.       char    testByte[4];
  347.     } endianTest;
  348.     int swapFlag;
  349.  
  350.     /*
  351.      * Determine if we are running on a big endian or a
  352.      * little endian machine. The binary data files are
  353.      * always stored in big endian format, so if this is
  354.      * a little endian machine we may have to swap bytes.
  355.      */
  356.     endianTest.testWord = 1;
  357.     if (endianTest.testByte[0] == 1)
  358.     {
  359.       swapFlag = TRUE;
  360.     } else {
  361.       swapFlag = FALSE;
  362.     }
  363.  
  364.     /*
  365.      * Obtain program name
  366.      */
  367.     Str_Dup(&self_name, argv[0]);
  368.  
  369.     /*
  370.      * Format time string
  371.      */
  372.     strftime(&time_string[0], sizeof(time_string), "%A, %B %d, %Y (%r %Z)", localtime(&now));
  373.  
  374.     /*
  375.      * Scan command line options
  376.      */
  377.     while ((option = getopt(argc, argv, FLAGS)) != EOF)
  378.     {
  379.         switch (option)
  380.         {
  381.     case 'b':    /* Binary output (ASCII input) */
  382.     case 'B':
  383.         output_mode = BINARY;
  384.         break;
  385.  
  386.     case 'a':    /* ASCII output (binary input) */
  387.     case 'A':
  388.         output_mode = ASCII;
  389.         break;
  390.  
  391.     case 'v':    /* Verbose mode */
  392.     case 'V':
  393.         verbose = True;
  394.         break;
  395.  
  396.     case 'm':    /* Mesh input file type */
  397.     case 'M':
  398.         input_type = MESH;
  399.         break;
  400.  
  401.     case 'o':    /* Polygon (object) input file type */
  402.     case 'O':
  403.     case 'p':
  404.     case 'P':
  405.         input_type = POLYGON;
  406.         break;
  407.  
  408.     case 'c':    /* Add comments to ASCII output */
  409.     case 'C':
  410.         comments = True;
  411.         break;
  412.  
  413.     case '?':    /* On-line help */
  414.     case 'h':
  415.     case 'H':
  416.     default:
  417.         Show_Help_Text();
  418.         exit(0);
  419.     } /* switch */
  420.     } /* while */
  421.  
  422.     /*
  423.      * Obtain input and output file paths 
  424.      */
  425.     if (optind < argc)
  426.     {
  427.     Str_Dup(&input_file_path, argv[optind]);
  428.  
  429.     if (++optind < argc)
  430.         Str_Dup(&output_file_path, argv[optind]);
  431.     }
  432.  
  433.     if (verbose)
  434.     {
  435.     fprintf(stderr, "Converting %s files to %s...\n",
  436.             (input_type == MESH ? "mesh" : "polygon"),
  437.             (output_mode == BINARY ? "binary" : "ASCII"));
  438.  
  439.         if (input_file_path == NULL               ||
  440.         *input_file_path == '\0'              ||
  441.             strcmp(input_file_path, "stdin") == 0 || 
  442.         strcmp(input_file_path, "STDIN") == 0)
  443.         fprintf(stderr, "\tInput: standard tty input\n");
  444.  
  445.     else if (input_type == MESH)
  446.         fprintf(stderr, "\tInput: %s\n", input_file_path);
  447.  
  448.         else
  449.     {
  450.         register uint32 i;
  451.  
  452.         fprintf(stderr, "\tInput:\n");
  453.         for (i = 0; i < N_POLY_TYPES; i++)
  454.         fprintf(stderr, "\t\t%s%s (%s)\n", input_file_path, poly_table[i].ext, poly_table[i].desc);
  455.     } /* else */
  456.  
  457.         if (output_file_path == NULL                ||
  458.         *output_file_path == '\0'               ||
  459.             strcmp(output_file_path, "stdout") == 0 || 
  460.         strcmp(output_file_path, "STDOUT") == 0)
  461.         fprintf(stderr, "\tOutput: standard tty output\n");
  462.  
  463.     else if (input_type == MESH)
  464.         fprintf(stderr, "\tOutput: %s\n", output_file_path);
  465.  
  466.         else
  467.     {
  468.         register uint32 i;
  469.  
  470.         fprintf(stderr, "\tOutput:\n");
  471.         for (i = 0; i < N_POLY_TYPES; i++)
  472.         fprintf(stderr, "\t\t%s%s (%s)\n", output_file_path, poly_table[i].ext, poly_table[i].desc);
  473.     } /* else */
  474.  
  475.     if (output_mode == ASCII && comments)
  476.         fprintf(stderr, "\tComments will be inserted in output\n");
  477.     fprintf(stderr, "\n");
  478.         if (swapFlag)
  479.             fprintf(stderr, "Running on a little endian machine, binary data will be byte swapped\n");
  480.         else
  481.             fprintf(stderr, "Running on a big endian machine, binary data will not be byte swapped\n");
  482.     } /* if */
  483.  
  484.     /*
  485.      * Process the files
  486.      */
  487.     switch (input_type)
  488.     {
  489.     case MESH:
  490.         /*
  491.          * Open input and output files
  492.          */
  493.         if (input_file_path == NULL               ||
  494.         *input_file_path == '\0'              ||
  495.             strcmp(input_file_path, "stdin") == 0 || 
  496.         strcmp(input_file_path, "STDIN") == 0)
  497.         {
  498.         if (verbose)
  499.                 fprintf(stderr, "%s: Reading MESH data from standard input...\n", self_name);
  500.             fp_input = stdin;
  501.         } /* if */
  502.     
  503.         else if ((fp_input = fopen(input_file_path, "r")) == NULL)
  504.         Error(FATAL, __FILE__, __LINE__, "main", 
  505.             "Cannot open MESH file '%s' for input", input_file_path);
  506.     
  507.         if (output_file_path == NULL                ||
  508.         *output_file_path == '\0'               ||
  509.             strcmp(output_file_path, "stdout") == 0 ||
  510.         strcmp(output_file_path, "STDOUT") == 0)
  511.         {
  512.         if (verbose)
  513.                 fprintf(stderr, "%s: Output MESH data to standard output...\n", self_name);
  514.             fp_output = stdout;
  515.         } /* if */
  516.  
  517.         else if ((fp_output = fopen(output_file_path, "w")) == NULL)
  518.         Error(FATAL, __FILE__, __LINE__, "main", 
  519.             "Cannot open MESH file '%s' for output", output_file_path);
  520.  
  521.     /*
  522.      * MESH conversion
  523.      */
  524.     {
  525.         uint32         count, count_swap, section = 1;
  526.         register uint     i;
  527.         float32        vector[3], vector_swap[3];
  528.  
  529.         /*
  530.          * Write output header
  531.          */
  532.         if ((output_mode == ASCII) && comments)
  533.         {
  534.         fprintf(fp_output, "#\n");
  535.         fprintf(fp_output, "# Mesh output file generated from input\n");
  536.         fprintf(fp_output, "# file \"%s\"\n", input_file_path);
  537.         fprintf(fp_output, "# %s\n", time_string);
  538.         fprintf(fp_output, "#\n");
  539.         } /* if */
  540.  
  541.         while (!feof(fp_input))
  542.         {
  543.         if (verbose)
  544.             fprintf(stderr, "Converting section %d...\n", section);
  545.  
  546.         /*
  547.          * Read / write vector count
  548.          */
  549.         switch (output_mode)
  550.         {
  551.         case ASCII:
  552.                 if (fread(&count, sizeof(count), 1, fp_input) == 1)
  553.             {
  554.                         if (swapFlag) Swap32((void *) &count, (void *) &count, 1);
  555.                 if (comments)
  556.                     fprintf(fp_output, "%u # SECTION %d COUNT\n", count, section);
  557.                 else
  558.                     fprintf(fp_output, "%u\n", count);
  559.             } /* if */
  560.             else
  561.             continue;
  562.             break;
  563.         case BINARY:
  564.             Scan(fp_input);
  565.             if (fscanf(fp_input, "%u", &count) > 0)
  566.             {
  567.                         if (swapFlag)
  568.                         {
  569.                           Swap32((void *) &count, (void *) &count_swap, 1);
  570.                           ptr = (void *) &count_swap;
  571.                         } else {
  572.                           ptr = (void *) &count;
  573.                         }
  574.                 if (fwrite(ptr, sizeof(count), 1, fp_output) != 1)
  575.                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  576.             }
  577.             else
  578.             continue;
  579.             break;
  580.         } /* switch */
  581.  
  582.         /*
  583.          * Read / write vectors
  584.          */
  585.         switch (output_mode)
  586.         {
  587.         case ASCII:
  588.             if (comments)
  589.             fprintf(fp_output, "# SECTION %d VECTORS\n", section);
  590.  
  591.             for (i = 0; i < count; i++)
  592.             {
  593.                     if (fread(vector, sizeof(float32), 3, fp_input) != 3)
  594.                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  595.                         if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  596.  
  597.             if (comments)
  598.                 fprintf(fp_output, "\t%f %f %f # vector[%d of %d]\n",
  599.                     vector[0], vector[1], vector[2], i + 1, count);
  600.             else
  601.                 fprintf(fp_output, "%f %f %f\n", vector[0], vector[1], vector[2]);
  602.             }
  603.             break;
  604.         case BINARY:
  605.             for (i = 0; i < count; i++)
  606.             {
  607.             Scan(fp_input);
  608.                 if (fscanf(fp_input, "%f %f %f", &vector[0], &vector[1], &vector[2]) < 0)
  609.                 Error(FATAL, __FILE__, __LINE__, "main", 
  610.                     "Found EOF while reading vector %d in file '%s'", i + 1, input_file_path);
  611.  
  612.                         if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  613.                 if (fwrite(vector, sizeof(float32), 3, fp_output) != 3)
  614.                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  615.             }
  616.             break;
  617.         } /* switch */
  618.  
  619.         if (verbose)
  620.             fprintf(stderr, "\tWrote %d vectors\n", count);
  621.         fflush(fp_output);
  622.  
  623.         /*
  624.          * Read / write normals
  625.          */
  626.         switch (output_mode)
  627.         {
  628.         case ASCII:
  629.             if (comments)
  630.             fprintf(fp_output, "# SECTION %d NORMALS\n", section);
  631.  
  632.             for (i = 0; i < count; i++)
  633.             {
  634.                     if (fread(vector, sizeof(float32), 3, fp_input) != 3)
  635.                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  636.                         if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  637.  
  638.             if (comments)
  639.                 fprintf(fp_output, "\t%f %f %f # normal[%d of %d]\n",
  640.                     vector[0], vector[1], vector[2], i + 1, count);
  641.             else
  642.                 fprintf(fp_output, "%f %f %f\n", vector[0], vector[1], vector[2]);
  643.             }
  644.             break;
  645.         case BINARY:
  646.             for (i = 0; i < count; i++)
  647.             {
  648.             Scan(fp_input);
  649.                 if (fscanf(fp_input, "%f %f %f", &vector[0], &vector[1], &vector[2]) < 0)
  650.                 Error(FATAL, __FILE__, __LINE__, "main", 
  651.                     "Found EOF while reading normal %d in file '%s'", i + 1, input_file_path);
  652.  
  653.                         if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  654.                 if (fwrite(vector, sizeof(float32), 3, fp_output) != 3)
  655.                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  656.             }
  657.             break;
  658.         } /* switch */
  659.  
  660.         if (verbose)
  661.             fprintf(stderr, "\tWrote %d normals\n", count);
  662.         fflush(fp_output);
  663.  
  664.         ++section;
  665.         } /* while */
  666.  
  667.         if (verbose)
  668.         fprintf(stderr, "EOF reached on MESH file\n", count);
  669.     } /* case MESH */
  670.  
  671.     if (fp_input != stdin)
  672.         fclose(fp_input);
  673.     if (fp_output != stdout)
  674.         fclose(fp_output);
  675.     break;
  676.  
  677.     case POLYGON:
  678.     {
  679.         register uint32     poly_i;
  680.         char        *save_input_path = NULL;
  681.         char        *save_output_path = NULL;
  682.  
  683.         /*
  684.           * Retain file path prefixes
  685.          */
  686.         Str_Dup(&save_input_path, input_file_path);
  687.         Str_Dup(&save_output_path, output_file_path);
  688.  
  689.         for (poly_i = 0; poly_i < N_POLY_TYPES; poly_i++)
  690.         {
  691.         /*
  692.          * Restore file path prefixes
  693.          */
  694.         Str_Dup(&input_file_path, save_input_path);
  695.         Str_Dup(&output_file_path, save_output_path);
  696.  
  697.             /*
  698.               * Open input and output files
  699.               */
  700.             if (input_file_path == NULL               ||
  701.                 *input_file_path == '\0'              ||
  702.                     strcmp(input_file_path, "stdin") == 0 || 
  703.                 strcmp(input_file_path, "STDIN") == 0)
  704.             {
  705.                 if (verbose)
  706.                     fprintf(stderr, "%s: Reading POLYGON %s from standard input...\n",
  707.                 self_name, poly_table[poly_i].desc);
  708.                     fp_input = stdin;
  709.             } /* if */
  710.     
  711.             else 
  712.         {
  713.             Str_Append(&input_file_path, poly_table[poly_i].ext, NULL);
  714.  
  715.             if ((fp_input = fopen(input_file_path, "r")) == NULL)
  716.                     Error(FATAL, __FILE__, __LINE__, "main", 
  717.                       "Cannot open POLYGON %s file '%s' for input", 
  718.                   poly_table[poly_i].desc, input_file_path);
  719.         } /* else */
  720.         
  721.             if (output_file_path == NULL                ||
  722.                 *output_file_path == '\0'               ||
  723.                     strcmp(output_file_path, "stdout") == 0 ||
  724.                 strcmp(output_file_path, "STDOUT") == 0)
  725.             {
  726.                 if (verbose)
  727.                     fprintf(stderr, "%s: Output POLYGON %s to standard output...\n",
  728.                 self_name, poly_table[poly_i].desc);
  729.                     fp_output = stdout;
  730.             } /* if */
  731.  
  732.             else
  733.         {
  734.             Str_Append(&output_file_path, poly_table[poly_i].ext, NULL);
  735.  
  736.             if ((fp_output = fopen(output_file_path, "w")) == NULL)
  737.                     Error(FATAL, __FILE__, __LINE__, "main", 
  738.                       "Cannot open POLYGON %s file '%s' for output", 
  739.                   poly_table[poly_i].desc, output_file_path);
  740.         } /* else */
  741.     
  742.         /*
  743.           * POLYGON conversion
  744.           */
  745.         if (verbose)
  746.             fprintf(stderr, "Processing Polygon %s file...\n", poly_table[poly_i].desc);
  747.  
  748.             /*
  749.               * Write output header
  750.               */
  751.             if ((output_mode == ASCII) && comments)
  752.         {
  753.             fprintf(fp_output, "#\n");
  754.             fprintf(fp_output, "# Polygon %s file generated from input\n", poly_table[poly_i].desc);
  755.             fprintf(fp_output, "# file \"%s\"\n", input_file_path);
  756.             fprintf(fp_output, "# %s\n", time_string);
  757.             fprintf(fp_output, "#\n");
  758.             } /* if */
  759.  
  760.         switch (poly_table[poly_i].type)
  761.         {
  762.         case COORDINATES:
  763.             {
  764.                 uint32        count = 0;
  765.                 uint32        vertex_number;
  766.                 float32        vector[3];
  767.  
  768.                 while (!feof(fp_input))
  769.                 {
  770.                 /*
  771.                   * Read / write coordinates
  772.                   */
  773.                 switch (output_mode)
  774.                 {
  775.                 case ASCII:
  776.                             if (fread(vector, sizeof(float32), 3, fp_input) == 3)
  777.                 {
  778.                                     if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  779.  
  780.                         if (comments)
  781.                             fprintf(fp_output, "%u,%f,%f,%f # coordinate[%d]\n",
  782.                             count + 1, vector[0], vector[1], vector[2], count + 1);
  783.                         else
  784.                             fprintf(fp_output, "%u,%f,%f,%f\n",
  785.                             count + 1, vector[0], vector[1], vector[2]);
  786.                         ++count;
  787.                 } /* if */
  788.                     break;
  789.  
  790.                 case BINARY:
  791.                 Scan(fp_input);
  792.                     if (fscanf(fp_input, "%u,%f,%f,%f", &vertex_number, &vector[0], &vector[1], &vector[2]) > 0)
  793.                 {
  794.  
  795.                                     if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  796.                         if (fwrite(vector, sizeof(float32), 3, fp_output) != 3)
  797.                         Error(FATAL, __FILE__, __LINE__, "main", NULL);
  798.                         ++count;
  799.                 } /* if */
  800.                     break;
  801.                 } /* switch */
  802.             } /* while */
  803.  
  804.             if (verbose)
  805.                 fprintf(stderr, "\tConverted %d coordinates\n", count);
  806.             } /* case COORDINATES */
  807.             break;
  808.  
  809.         case ELEMENTS:
  810.             {
  811.                 uint32        count = 0, n_lines = 0, n_lines_swap;
  812.                 uint32        tag_len, tag_len_swap;
  813.                 uint32        n_vertices, n_vertices_swap;
  814.                 char        *tag = NULL, *prev_tag = NULL, *store = NULL;
  815.             fpos_t        fpos_prev;
  816.  
  817.                 while (!feof(fp_input))
  818.                 {
  819.                 /*
  820.                   * Read / write elements
  821.                   */
  822.                 switch (output_mode)
  823.                 {
  824.                 case ASCII:
  825.                 /*
  826.                   * Read header
  827.                   */
  828.                     if (fread(&tag_len, sizeof(tag_len), 1, fp_input) == 1)
  829.                 {
  830.                     register uint32     line;
  831.  
  832.                                     if (swapFlag) Swap32((void *) &tag_len, (void *) &tag_len, 1);
  833.  
  834.                         Expand(&tag, tag_len * sizeof(char));
  835.                         if (fread(tag, sizeof(char), tag_len, fp_input) != tag_len)
  836.                         Error(FATAL, __FILE__, __LINE__, "main", NULL);
  837.  
  838.                                     /* tag is string data, so no byte swapping is necessary */
  839.  
  840.                         if (fread(&n_lines, sizeof(n_lines), 1, fp_input) != 1)
  841.                         Error(FATAL, __FILE__, __LINE__, "main", NULL);
  842.                                     if (swapFlag) Swap32((void *) &n_lines, (void *) &n_lines, 1);
  843.  
  844.                     for (line = 0; line < n_lines; line++)
  845.                     {
  846.                     register uint32 i;
  847.  
  848.                     if (fread(&n_vertices, sizeof(n_vertices), 1, fp_input) != 1)
  849.                             Error(FATAL, __FILE__, __LINE__, "main", NULL);
  850.                                         if (swapFlag) Swap32((void *) &n_vertices, (void *) &n_vertices, 1);
  851.  
  852.                         Expand(&store, n_vertices * sizeof(int32));
  853.                         if (fread(store, sizeof(int32), n_vertices, fp_input) != n_vertices)
  854.                             Error(FATAL, __FILE__, __LINE__, "main", NULL);
  855.                                         if (swapFlag) Swap32((void *) store, (void *) store, n_vertices);
  856.  
  857.                         fprintf(fp_output, "%s ", tag);
  858.                         for (i = 0; i < n_vertices; i++)
  859.                         fprintf(fp_output, "%d ", ((int32 *)store)[i]);
  860.                         if (comments)
  861.                         fprintf(fp_output, "# line %d, (%s line %d, %d elements)\n",
  862.                             count + 1, tag, line + 1, n_vertices);
  863.                         else
  864.                         fprintf(fp_output, "\n");
  865.                             ++count;
  866.                     }
  867.                 } /* if */
  868.                 break;
  869.  
  870.                 case BINARY:
  871.                 /*
  872.                  * If starting out, make some space for the line tags
  873.                  */
  874.                 if (count == 0)
  875.                     Expand(&tag, 128 * sizeof(char));
  876.  
  877.                 Scan(fp_input);
  878.                 if (fscanf(fp_input, "%s", tag) > 0)
  879.                 {
  880.                         int32        element;
  881.  
  882.                     /*
  883.                      * Create a header line and save the line count position
  884.                      */
  885.                     if ((count == 0) || (strcmp(tag, prev_tag) != 0))
  886.                     {
  887.                     /*
  888.                      * Fill in prior line count
  889.                      */
  890.                     if (count != 0)
  891.                     {
  892.                         fpos_t    fpos_curr;
  893.  
  894.                         fgetpos(fp_output, &fpos_curr);
  895.                         fsetpos(fp_output, &fpos_prev);
  896.                                             if (swapFlag)
  897.                                             {
  898.                                               Swap32((void *) &n_lines, (void *) &n_lines_swap, 1);
  899.                                               ptr = (void *) &n_lines_swap;
  900.                                             } else {
  901.                                               ptr = (void *) &n_lines;
  902.                                             }
  903.                             if (fwrite(ptr, sizeof(n_lines), 1, fp_output) != 1)
  904.                                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  905.                         fsetpos(fp_output, &fpos_curr);
  906.                     } /* if */
  907.  
  908.                         tag_len = strlen(tag) + 1;
  909.                                         if (swapFlag)
  910.                                         {
  911.                                           Swap32((void *) &tag_len, (void *) &tag_len_swap, 1);
  912.                                           ptr = (void *) &tag_len_swap;
  913.                                         } else {
  914.                                           ptr = (void *) &tag_len;
  915.                                         }
  916.                         if (fwrite(ptr, sizeof(tag_len), 1, fp_output) != 1)
  917.                             Error(FATAL, __FILE__, __LINE__, "main", NULL);
  918.  
  919.                                         /* No need to swap string data */
  920.  
  921.                         if (fwrite(tag, sizeof(char), tag_len, fp_output) != tag_len)
  922.                             Error(FATAL, __FILE__, __LINE__, "main", NULL);
  923.  
  924.                     n_lines = 0;
  925.                     fgetpos(fp_output, &fpos_prev);
  926.                                         if (swapFlag)
  927.                                         {
  928.                                           Swap32((void *) &n_lines, (void *) &n_lines_swap, 1);
  929.                                           ptr = (void *) &n_lines_swap;
  930.                                         } else {
  931.                                           ptr = (void *) &n_lines;
  932.                                         }
  933.                         if (fwrite(ptr, sizeof(n_lines), 1, fp_output) != 1)
  934.                             Error(FATAL, __FILE__, __LINE__, "main", NULL);
  935.  
  936.                     Str_Dup(&prev_tag, tag);
  937.                     } /* if */
  938.  
  939.                     n_vertices = 0;
  940.                     Scan(fp_input);
  941.                     while (fscanf(fp_input, "%d", &element) > 0)
  942.                     {
  943.                         Expand(&store, (n_vertices + 1) * sizeof(int32));
  944.                         ((int32 *)store)[n_vertices] = element;
  945.                         ++n_vertices;
  946.                         Scan(fp_input);
  947.                     } /* while */
  948.  
  949.                                     if (swapFlag)
  950.                                     {
  951.                                       Swap32((void *) &n_vertices, (void *) &n_vertices_swap, 1);
  952.                                       ptr = (void *) &n_vertices_swap;
  953.                                     } else {
  954.                                       ptr = (void *) &n_vertices;
  955.                                     }
  956.                     if (fwrite(ptr, sizeof(n_vertices), 1, fp_output) != 1)
  957.                         Error(FATAL, __FILE__, __LINE__, "main", NULL);
  958.  
  959.                                     if (swapFlag) Swap32((void *) store, (void *) store, n_vertices);
  960.                     if (fwrite(store, sizeof(int32), n_vertices, fp_output) != n_vertices)
  961.                         Error(FATAL, __FILE__, __LINE__, "main", NULL);
  962.  
  963.                         ++count;
  964.                     ++n_lines;
  965.                 } /* if */
  966.                 break;
  967.                 } /* switch */
  968.             } /* while */
  969.  
  970.             /*
  971.              * Fill in outstanding prior line count, if in BINARY output mode
  972.              */
  973.             if ((output_mode == BINARY) && (n_lines != 0))
  974.             {
  975.                 fpos_t    fpos_curr;
  976.  
  977.                 fgetpos(fp_output, &fpos_curr);
  978.                 fsetpos(fp_output, &fpos_prev);
  979.                             if (swapFlag)
  980.                             {
  981.                               Swap32((void *) &n_lines, (void *) &n_lines_swap, 1);
  982.                               ptr = (void *) &n_lines_swap;
  983.                             } else {
  984.                               ptr = (void *) &n_lines;
  985.                             }
  986.                 if (fwrite(ptr, sizeof(n_lines), 1, fp_output) != 1)
  987.                 Error(FATAL, __FILE__, __LINE__, "main", NULL);
  988.                 fsetpos(fp_output, &fpos_curr);
  989.             } /* if */
  990.  
  991.             if (verbose)
  992.                 fprintf(stderr, "\tConverted %d element records\n", count);
  993.             } /* ELEMENTS */
  994.             break;
  995.  
  996.         case NORMS:
  997.             {
  998.             uint32         count = 0;
  999.             float32        vector[3];
  1000.  
  1001.                 while (!feof(fp_input))
  1002.                 {
  1003.                 /*
  1004.                   * Read / write vector normals
  1005.                   */
  1006.                 switch (output_mode)
  1007.                 {
  1008.                 case ASCII:
  1009.                             if (fread(vector, sizeof(float32), 3, fp_input) == 3)
  1010.                 {
  1011.                                     if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  1012.                         if (comments)
  1013.                             fprintf(fp_output, "%f %f %f # normal[%d]\n", vector[0], vector[1], vector[2], count + 1);
  1014.                         else
  1015.                             fprintf(fp_output, "%f %f %f\n", vector[0], vector[1], vector[2]);
  1016.                         ++count;
  1017.                 } /* if */
  1018.                 break;
  1019.  
  1020.                 case BINARY:
  1021.                 Scan(fp_input);
  1022.                     if (fscanf(fp_input, "%f %f %f", &vector[0], &vector[1], &vector[2]) > 0)
  1023.                 {
  1024.                                     if (swapFlag) Swap32((void *) vector, (void *) vector, 3);
  1025.                         if (fwrite(vector, sizeof(float32), 3, fp_output) != 3)
  1026.                         Error(FATAL, __FILE__, __LINE__, "main", NULL);
  1027.                         ++count;
  1028.                 } /* if */
  1029.                     break;
  1030.                 } /* switch */
  1031.             } /* while */
  1032.  
  1033.             if (verbose)
  1034.                 fprintf(stderr, "\tConverted %d normals\n", count);
  1035.             } /* NORMS */
  1036.             break;
  1037.         } /* switch */
  1038.  
  1039.         fflush(fp_output);
  1040.  
  1041.         if (fp_input != stdin)
  1042.                 fclose(fp_input);
  1043.         if (fp_output != stdout)
  1044.                 fclose(fp_output);
  1045.         } /* for */
  1046.     } /* case POLYGON */
  1047.     break;
  1048.  
  1049.     } /* switch */
  1050. } /* main */
  1051.